/**
 * @Copyright ®2015 Sinosoft Co. Ltd. All rights reserved.<br/>
 * 项目名称 : 电子商务云服务平台
 * 创建日期 : 2016年6月28日
 * 修改历史 : 
 *     1. [2016年6月30日]修改文件 by chihouliang
 * 添加Javadoc注释，更新代码规范，静态工具类增加private构造函数
 */
package com.gavinwind.inspay.common.util;

import com.gavinwind.inspay.common.logger.PlatformLogger;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.lang.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 
 * 【Http发送报文，表单提交工具类】
 * @author 
 * @date 2016年6月29日 上午11:58:37 
 * @version 1.0
 */
@SuppressWarnings("deprecation")
public class HttpClientUtil {

    private HttpClientUtil() {}

    /**日志*/
    private static PlatformLogger logger = PlatformLogger.getLogger(HttpClientUtil.class);
    /**编码：utf-8*/
    public static final String CHARSET_UTF_8 = "UTF-8";
    /**编码GBK*/
    public static final String CHARSET_GBK = "GBK";
    /**cContentType 类型text/tHtml*/
    public static final String CONTENT_TYPE_TEXT_HTML = "text/tHtml";
    /**提交方式application/x-www-form-urlencoded*/
    public static final String CONTENT_TYPE_APPLICATION_FORM = "application/x-www-form-urlencoded";
    /**HttpClient对象*/
    private static HttpClient httpClient = null;
    /**提交方式get*/
    private static final String HTTP_METHOD_GET = "GET";
    //    private static final String HTTP_METHOD_POST = "POST";
    /**CONTENT_TYPE类型text/tHtml;charset=UTF-8*/
    private static final String CONTENT_TYPE = "text/tHtml;charset=UTF-8";
    static {
        Protocol tMyhttps = new Protocol("https", new HttpsSecureProtocolSocketFactory(), 443);
        Protocol.registerProtocol("https", tMyhttps);
        httpClient = new HttpClient();
    }

    /**
     * post方式提交表单数据
     * @param cUrlStr 请求地址
     * @param cParamMap 使用map存放需要提交的数据，以键值对形式存储
     * @return 服务器相应信息
     * @throws Exception
     */
    public static String originalPostData(String cUrlStr, Map<String, String> cParamMap) throws Exception {
        UTF8PostMethod tProcPost = new UTF8PostMethod(cUrlStr);
        Set<String> tKeySet = cParamMap.keySet();

        for (Object tKey : tKeySet) {
            String tKeyValue = String.valueOf(tKey);
            String tValue = (String) cParamMap.get(tKeyValue);
            if (tValue == null) {
                tValue = "";
            }
            tProcPost.addParameter(tKeyValue, tValue);
        }

        httpClient.executeMethod(tProcPost);

        // 读取内容
        byte[] tDataArr = null;
        String tResult = null;
        try {
            tDataArr = tProcPost.getResponseBody();
            tResult = new String(tDataArr, "UTF-8");
            //tResult = tProcPost.getResponseBodyAsString();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return tResult;

    }

    /** 
     * 发送报文到支付系统
     * @Title: sendPaymentXml 
     * @param cParamMap 参数
     * @param cXml 报文
     * @param cUrl 请求地址
     * @return 服务器响应信息
     * @throws Exception
    */
    public static String sendPaymentXml(Map<String, String> cParamMap, String cXml, String cUrl) throws Exception {
        cParamMap.put("dataXml", cXml);
        return originalPostData(cUrl, cParamMap);
    }

    /**
     * 提交数据
     * @param cUrlStr 请求地址
     * @param cParamMap 参数
     * @param cCharsetType 编码方式，例如UTF-8 GBK等
     * @return 服务器响应信息
     * @throws Exception
     */
    public static String postData(String cUrlStr, Map<String, String> cParamMap, String cCharsetType) throws Exception {

        UTF8PostMethod tProcPost = new UTF8PostMethod(cUrlStr);

        Set<String> tKeySet = cParamMap.keySet();

        for (Object tKey : tKeySet) {
            String tKeyValue = String.valueOf(tKey);
            String tValue = (String) cParamMap.get(tKeyValue);
            if (tValue == null) {
                tValue = "";
            }
            tProcPost.addParameter(tKeyValue, tValue);
        }
        logger.info("HTTP 请求开始");
        //链接超时
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(60000);
        //读取超时
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(60000);
        int tStatusCode = httpClient.executeMethod(tProcPost);
        logger.info("HTTP 返回状态码：" + tStatusCode);
        // 读取内容
        InputStream tResInputStream = null;
        StringBuffer tHtml = new StringBuffer();
        try {
            tResInputStream = tProcPost.getResponseBodyAsStream();
            // 处理内容
            BufferedReader tReader = new BufferedReader(new InputStreamReader(tResInputStream, cCharsetType));
            String tTempBf = null;
            while ((tTempBf = tReader.readLine()) != null) {

                tHtml.append(tTempBf);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (tResInputStream != null) {
                tResInputStream.close();
            }
        }
        logger.info("HTTP 请求结束");
        return new String(tHtml.toString().getBytes(cCharsetType), cCharsetType);
    }

    /**
     * post方式提交数据，使用 GBK编码
     * @param cUrlStr 请求地址
     * @param cParamMap 参数
     * @return 服务器响应信息
     * @throws Exception
     */
    public static String postData(String cUrlStr, Map<String, String> cParamMap) throws Exception {
        return postData(cUrlStr, cParamMap, "GBK");
    }

    // modify by wangxulu 2013-05-21 end
    /**
     * 
     * http请求，json数据发送。utf-8编码
     * @param cUrlStr 请求地址
     * @param cXmlData 请求参数报文（json数据）
     * @return 服务器响应信息
     * @throws Exception
     */
    public static String postJsonData(String cUrlStr, String cXmlData) throws Exception {
        return postJsonData(cUrlStr, cXmlData, "UTF-8");
    }
    
    /**
     * http请求，提交json数据
     * @param cUrlStr 请求地址
     * @param cXmlData 请求数据
     * @param cCharsetType 编码方式
     * @return 服务器响应信息
     * @throws Exception
     */
    public static String postJsonData(String cUrlStr, String cXmlData, String cCharsetType) throws Exception {
        UTF8PostMethod tPost = new UTF8PostMethod(cUrlStr);
        tPost.setRequestBody(cXmlData);
        httpClient.executeMethod(tPost);
        return getResponseXml(tPost.getResponseBodyAsStream());
    }
    
    /**
     * 
     * http请求，get方式，UTF-8编码
     * @param cUrlStr 请求地址
     * @return 服务器响应
     * @throws Exception
     */
    public static String originalGetData(String cUrlStr) throws Exception {
        return originalGetData(cUrlStr, new HashMap<String, String>(), "UTF-8");
    }

    /**
     * http请求，get方式，UTF-8编码
     * @param cUrlStr 请求地址
     * @param cParamMap 请求参数
     * @return 服务器响应信息
     * @throws Exception
     */
    public static String originalGetData(String cUrlStr, Map<String, String> cParamMap) throws Exception {
        return originalGetData(cUrlStr, cParamMap, "UTF-8");
    }
    
    /**
     * 
     * http请求，get方式，UTF-8编码
     * @param cUrlStr 请求地址
     * @param cParamMap 请求参数
     * @param cCharsetType 编码
     * @return 服务器响应信息
     * @throws Exception 系统异常
     */
    public static String originalGetData(String cUrlStr, Map<String, String> cParamMap, String cCharsetType) throws Exception {
        int i = 0;
        char tChar = 0;
        if (cParamMap.size() > 0) {
            // param += "?";
            Set<String> tKeySet = cParamMap.keySet();
            for (Object tKey : tKeySet) {
                i = cUrlStr.indexOf("?");
                if (i > 0) {
                    tChar = '&';
                } else {
                    tChar = '?';
                }

                String tKeyValue = String.valueOf(tKey);
                String tValue = (String) cParamMap.get(tKeyValue);
                if (tValue == null) {
                    tValue = "";
                } else {
                    tValue = URLEncoder.encode(tValue, cCharsetType);
                }
                cUrlStr += (tChar + tKeyValue + "=" + tValue);
            }
        }

        GetMethod tProcGet = new GetMethod(cUrlStr);
        httpClient.executeMethod(tProcGet);

        // 读取内容
        String tResult = null;
        try {
            tResult = tProcGet.getResponseBodyAsString();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return tResult;
    }
    /**
     * 
     * 使用UTF-8编码格式读取输入流中数据
     * @param cInputStream 输入流
     * @return 输入流中数据
     * @throws Exception
     */
    public static String getResponseXml(InputStream cInputStream) throws Exception {
        BufferedReader tBufferedReader = new BufferedReader(new InputStreamReader(cInputStream, "UTF-8"));
        StringBuffer tBuffer = new StringBuffer();
        String tDemo = "";
        while ((tDemo = tBufferedReader.readLine()) != null) {
            tBuffer.append(tDemo);
        }
        String tXml = tBuffer.toString();
        return tXml;
    }

    /**
     * post方式提交数据，使用 UTF-8编码
     * @param cUrlStr 请求地址
     * @param cParamMap 参数
     * @return 服务器响应信息
     * @throws Exception
     */
    public static String postDataWithUTF8(String cUrlStr, Map<String, String> cParamMap) throws Exception {
        return postData(cUrlStr, cParamMap, "UTF-8");
    }

    /**
     * get方式提交数据
     * 
     * @param cUrlStr 请求地址
     * @param cParamMap 请求参数
     * @param cCharsetType 编码方式，如UTF-8 GBK
     * @return 服务器响应信息
     * @throws Exception
     */

    /**
     * 把请求地址和请求参数封装成get请求链接，get请求url格式：http://127.0.0.1:8080/test?id=1&name=san
     * @param cUrlStr 请求地址
     * @param cParamMap 请求参数
     * @return 拼接后的get请求方式url
     * @throws Exception
     */
    public static String getDataUrl(String cUrlStr, Map<String, String> cParamMap) throws Exception {
        int i = 0;
        char tChar = 0;
        if (cParamMap.size() > 0) {
            Set<String> tKeySet = cParamMap.keySet();
            for (Object tKey : tKeySet) {
                i = cUrlStr.indexOf("?");
                if (i > 0) {
                    tChar = '&';
                } else {
                    tChar = '?';
                }
                String tKeyValue = String.valueOf(tKey);
                String tValue = (String) cParamMap.get(tKeyValue);
                if (tValue == null) {
                    tValue = "";
                }
                cUrlStr += (tChar + tKeyValue + "=" + tValue);
            }
        }

        return cUrlStr;
    }

    /**
     * 把unicode表示形式的中文编码转换成中文字符串
     * @名称: 由UnionCode转为String
     * @作者: Chen.yulong
     * @创建于: 2011-8-29
     * @param cUnicode unicode编码表示汉字，例如\u0000
     * @return 中文表示字符串
     * @描述:
     */
    public static String tozhCN(String cUnicode) {
        StringBuffer tGbk = new StringBuffer();
        String[] tHex = cUnicode.split("\\\\u");
        for (int i = 1; i < tHex.length; i++) { // 注意要从 1 开始，而不是从0开始。第一个是空。
            int tDataArr = Integer.parseInt(tHex[i], 16); // 将16进制数转换为 10进制的数据。
            tGbk.append((char) tDataArr); // 强制转换为char类型就是我们的中文字符了。
        }
        return tGbk.toString();
    }

    /**
     * 把中文字符串转换为unicode表示的字符串形式
     * @名称: 由String转为UnionCode
     * @作者: Chen.yulong
     * @创建于: 2011-9-9
     * @param cZhStr 需要转换成unicode编码的字符串
     * @return 转换成unicode编码后的字符串表示
     * @描述:
     */
    public static String toUnicode(String cZhStr) {
        StringBuffer tUnicode = new StringBuffer();
        for (int i = 0; i < cZhStr.length(); i++) {
            char tChar = cZhStr.charAt(i);
            tUnicode.append("\\u" + Integer.toHexString(tChar));
        }
        return tUnicode.toString();
    }

    /**
     * 
     * http请求，get方式发送
     * @param cUrl 请求地址
     * @param cAueryString 查询String
     * @param cCharSet 编码
     * @param cContentType 请求content类型
     * @return 服务器响应信息
     */
    public static String getRequest(String cUrl, String cAueryString, String cCharSet, String cContentType) {
        String tEncode = StringUtils.isNotEmpty(cCharSet) ? cCharSet : HttpClientUtil.CHARSET_UTF_8;
        final String tType = StringUtils.isNotEmpty(cContentType) ? cContentType : HttpClientUtil.CONTENT_TYPE_TEXT_HTML;

        String tEncodeUrl = cUrl;
        logger.info("tEncodeUrl:" + tEncodeUrl);
        try {
            tEncodeUrl = URIUtil.encodeQuery(cUrl, tEncode);
        } catch (URIException e) {
            e.printStackTrace();
        }
        logger.info("tEncodeUrl----------:" + tEncodeUrl);
        GetMethod tGet = new GetMethod(tEncodeUrl);
        tGet.addRequestHeader("Content-Type", tType + ";charset=" + tEncode);

        if (StringUtils.isNotEmpty(cAueryString)) {
            tGet.setQueryString(cAueryString);
        }
        logger.info("cUrl=" + cUrl);
        return get(tGet, tEncode);
    }
    
    /**
     * 
     * http请求，get方式，报文发送
     * @param cUrl 请求地址
     * @param cAueryString 报文数据
     * @return 服务器响应信息
     */
    public static String getRequest(String cUrl, String cAueryString) {
        return request(cUrl, HTTP_METHOD_GET, null, cAueryString);
    }

    /**
     * 
     * http请求，get方式请求，指定编码
     * @param cGet get方式请求
     * @param cCharSet 编码方式
     * @return 服务器响应信息
     */
    //私有化的方法没有使用
    private static String get(GetMethod cGet, String cCharSet) {
        HttpClient tHttpClient = new HttpClient();
        Integer tStatus = 0;
        InputStream tInputStream = null;

        try {
            tStatus = tHttpClient.executeMethod(cGet);
            tInputStream = cGet.getResponseBodyAsStream();
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("HttpClientUtil异常!"  , e);
        }
        logger.info("tStatus:{}" , tStatus.toString());
        return getResponse(tStatus, tInputStream, cCharSet);
    }

    /**
     * 
     * 获取服务器响应信息
     * @param cStatus 服务器返回状态码，例如200为成功
     * @param cInputStream 服务器返回文件流信息
     * @param cCharSet 解析编码方式
     * @return 服务器响应信息
     */
    private static String getResponse(int cStatus, InputStream cInputStream, String cCharSet) {
        String tEncode = StringUtils.isNotEmpty(cCharSet) ? cCharSet : HttpClientUtil.CHARSET_UTF_8;
        StringBuilder tBuilder = new StringBuilder();
        if (cStatus == HttpStatus.SC_OK && cInputStream != null) {
            try {
                BufferedReader tReader = new BufferedReader(new InputStreamReader(cInputStream, tEncode));
                String tLine = null;
                while ((tLine = tReader.readLine()) != null) {
                    tBuilder.append(tLine);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                logger.error("HttpClientUtil异常!", e);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("HttpClientUtil异常!", e);
            } finally {
                try {
                    cInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return tBuilder.toString();
    }

    /**
     * 
     * http请求 ，get或post请求。form表单参数提交或者报文发送
     * @param cUrl 请求地址
     * @param cMethod 请求方式，get 或post
     * @param cList 请求参数
     * @param cBody 当list请求参数为空时，进行报文数据发送
     * @return 服务器响应信息
     */
    private static String request(String cUrl, String cMethod, List<NameValuePair> cList, String cBody) {
        StringBuilder tBuilder = new StringBuilder();
        if (StringUtils.isEmpty(cUrl)) {
            return "";
        }
        HttpClient tHttpClient = new HttpClient();

        int tStatus = 0;
        InputStream tInputStream = null;
        if (cMethod.equalsIgnoreCase("get")) {
            String tEncodeUrl = cUrl;
            try {
                tEncodeUrl = URIUtil.encodeQuery(cUrl, CHARSET_UTF_8);
            } catch (URIException e) {
                e.printStackTrace();
            }
            GetMethod tGet = new GetMethod(tEncodeUrl);
            tGet.addRequestHeader("Content-Type", CONTENT_TYPE);

            if (cList != null && !cList.isEmpty()) {
                NameValuePair[] tArr = new NameValuePair[cList.size()];
                tGet.setQueryString(cList.toArray(tArr));
            } else if (StringUtils.isNotEmpty(cBody)) {
                tGet.setQueryString(cBody);
            }
            try {
                logger.info("tGet = " + tGet);
                tStatus = httpClient.executeMethod(tGet);
                tInputStream = tGet.getResponseBodyAsStream();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("HttpClientUtil异常!", e);
            }
        } else if (cMethod.equalsIgnoreCase("tPost")) {
            PostMethod tPost = new PostMethod(cUrl);
            tPost.addRequestHeader("Content-Type", CONTENT_TYPE);
            if (cList != null && !cList.isEmpty()) {
                NameValuePair[] tArr = new NameValuePair[cList.size()];
                tPost.setRequestBody(cList.toArray(tArr));
            } else if (StringUtils.isNotEmpty(cBody)) {
                tPost.setRequestBody(cBody);
            }
            try {
                tStatus = tHttpClient.executeMethod(tPost);
                tInputStream = tPost.getResponseBodyAsStream();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("HttpClientUtil异常!", e);
            }
        }

        if (tStatus == HttpStatus.SC_OK && tInputStream != null) {
            try {
                BufferedReader tReader = new BufferedReader(new InputStreamReader(tInputStream, CHARSET_UTF_8));
                String tLine = null;
                while ((tLine = tReader.readLine()) != null) {
                    tBuilder.append(tLine);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                logger.error("HttpClientUtil异常!", e);
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("HttpClientUtil异常!", e);
            } finally {
                try {
                    tInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return tBuilder.toString();
    }
}

/**
 * 重写PostMethod以解决UTF-8编码问题
 * 
 * @author adun
 */
class UTF8PostMethod extends PostMethod {
    public UTF8PostMethod(String cUrl) {
        super(cUrl);
    }

    @Override
    public String getRequestCharSet() {
        return "UTF-8";
    }
}
